package com.ydlclass.channelHandler.handler;

import com.ydlclass.ServiceConfig;
import com.ydlclass.YrpcBootstrap;
import com.ydlclass.enumeration.RequestType;
import com.ydlclass.enumeration.RespCode;
import com.ydlclass.protection.RateLimiter;
import com.ydlclass.protection.TokenBuketRateLimiter;
import com.ydlclass.transport.message.RequestPayload;
import com.ydlclass.transport.message.YrpcRequest;
import com.ydlclass.transport.message.YrpcResponse;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.SocketAddress;
import java.util.Map;

@Slf4j
public class MethodCallHandler extends SimpleChannelInboundHandler<YrpcRequest> {
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, YrpcRequest yrpcRequest) throws Exception {
        //1、先封装部分响应
        YrpcResponse yrpcResponse = new YrpcResponse();
        yrpcResponse.setRequestId(yrpcRequest.getRequestId());
        yrpcResponse.setCompressType(yrpcRequest.getCompressType());
        yrpcResponse.setSerializeType(yrpcRequest.getSerializeType());



        //2、完成限流相关的操作
        Channel channel = channelHandlerContext.channel();
        SocketAddress socketAddress = channel.remoteAddress();
        Map<SocketAddress, RateLimiter> everyIpRateLimiter = YrpcBootstrap.getInstance().getConfiguration().getEveryIpRateLimiter();

        RateLimiter rateLimiter = everyIpRateLimiter.get(socketAddress);
        if(rateLimiter == null){
            rateLimiter = new TokenBuketRateLimiter(5,5);
            everyIpRateLimiter.put(socketAddress,rateLimiter);
        }
        boolean allowRequest = rateLimiter.allowRequest();

        //限流
        if(!allowRequest){
            //需要封装响应并且返回
            yrpcResponse.setCode(RespCode.RATE_LIMIT.getCode());
        }else if(yrpcRequest.getRequestType() == RequestType.HEART_TYPE.getId()){
            //处理心跳请求
            yrpcResponse.setCode(RespCode.SUCCESS_HEART_BEAT.getCode());
        }else {
            /**------------------------------具体的调用过程--------------------------------**/
            //1.获取负载内容
            RequestPayload requestPayload = yrpcRequest.getRequestPayload();
            //2.根据负载内容进行方法调用
            try{
                Object result = callTargetMethod(requestPayload);
                if (log.isDebugEnabled()) {
                    log.debug("请求{}已经在服务端完成了方法调用.", yrpcRequest.getRequestId());
                }
                //3. 封装响应 响应码，响应类型
                yrpcResponse.setCode(RespCode.SUCCESS.getCode());
                yrpcResponse.setBody(result);
            } catch (Exception e){
                log.error("编号为{}的请求在调用过程中发生了异常",yrpcRequest.getRequestId(),e);
                yrpcResponse.setCode(RespCode.FAIL.getCode());
            }
        }
        //4.写出响应
        channel.writeAndFlush(yrpcResponse);

    }

    private Object callTargetMethod(RequestPayload requestPayload) {
        String interfaceName = requestPayload.getInterfaceName();
        String methodName = requestPayload.getMethodName();
        Class<?>[] parametersType = requestPayload.getParametersType();
        Object[] parametersValue = requestPayload.getParametersValue();

        //寻找到匹配的暴露出去的具体的实现
        ServiceConfig<?> serviceConfig = YrpcBootstrap.SERVERS_LIST.get(interfaceName);

        Object refImpl = serviceConfig.getRef();

        //通过反射调用 1.获取方法对象  2.执行invoke方法
        Object returnValue;
        try {
            Class<?> aClass = refImpl.getClass();
            Method method = aClass.getMethod(methodName, parametersType);
            returnValue = method.invoke(refImpl, parametersValue);
        } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
            log.error("调用服务{}的方法{}时，发生了异常",interfaceName,methodName,e);
            throw new RuntimeException(e);
        }
        return returnValue;
    }
}
